<!-- pdf预览组件，可以预览PDF -->
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import { NButton, NInput, NSpace, NSpin, useMessage } from 'naive-ui'
// 接收外部传入的pdf地址
const props = defineProps({
  pdfSrc: {
    type: String,
    default: '',
  },
})
// 接收父组件传递的事件，完成获取选中的文字和翻译内容
const emit = defineEmits<{
  (e: 'getSelectTxt', selectTxt: string): void
  (e: 'getTranslation', translation: string): void
}>()
const message = useMessage()
// 选中的文字
const getStr = ref('123')
// PDF src地址
const pdfURL = ref('')
// 挂载到pdfjs的地址
const fileURL = '/pdfjs-4.0.379-dist/web/viewer.html?file='

// 因为URL时时变化，所以需要计算属性
const getPDFURL = computed(() => {
  // 如果传入的pdfURL不为空，则使用传入的pdfURL
  if (props.pdfSrc != '')
    return fileURL + encodeURIComponent(props.pdfSrc)

  return fileURL + encodeURIComponent(pdfURL.value)
})

// 获取pdf_iframe的DOM
const pdfIframe = ref()
// pdfIframeContainer的DOM
const pdfIframeContainer = ref()

// 翻译按钮弹窗设置
const tagInfo = ref({
  visible: false,
  styleToEn: {
    position: 'absolute',
    top: '0px',
    left: '0px',
    zIndex: 9999,
  },
  styleToZh: {
    position: 'absolute',
    top: '0px',
    left: '0px',
    zIndex: 9999,
  },
})
// 翻译内容弹窗设置
const tagInput = ref({
  visible: false,
  content: '这是翻译内容',
  style: {
    position: 'absolute',
    top: '0px',
    left: '0px',
    zIndex: 9999,
  },
})

// 为PDF文件注册选中文本事件
function getSelectTxt(this: any) {
  // 获取DOM
  const iframe = pdfIframe.value
  let x = ''
  let y = ''
  let _x = ''
  let _y = ''
  // 选中文本事件
  iframe.onload = function () {
    // 鼠标点击监听
    iframe.contentDocument.addEventListener('mousedown', (e: any) => {
      x = e.pageX
      y = e.pageY
      // 隐藏翻译按钮
      tagInfo.value.visible = false
      tagInput.value.visible = false
    }, true)
    // 鼠标抬起监听
    iframe.contentDocument.addEventListener('mouseup', (e: any) => {
      _x = e.pageX
      _y = e.pageY
      if (x == _x && y == _y)
        return // 判断点击和抬起的位置，如果相同，则视为没有滑选，不支持双击选中
      const choose = iframe.contentWindow.getSelection().toString()
      getStr.value = choose
      // 触发父组件事件，获取选中的文字
      emit('getSelectTxt', choose)
      // 弹窗出现翻译按钮
      // 判断长度
      if (getStr.value.length > 0) {
        // 位置需要追加到当前鼠标位置，即需要加上iframe的位置左上角的坐标，获取iframe父级的位置
        const rect = pdfIframeContainer.value.getBoundingClientRect()
        const containerLeft = rect.left
        const containerTop = rect.top
        // 还需要计算滚动条位置
        const scrollTop = document.documentElement.scrollTop
        const scrollLeft = document.documentElement.scrollLeft
        tagInfo.value = {
          visible: true,
          styleToEn: {
            position: 'absolute',
            top: `${scrollTop + containerTop + _y + e.offsetY}px`,
            left: `${scrollLeft + containerLeft + _x + 20}px`,
            zIndex: 9999,
          },
          styleToZh: {
            position: 'absolute',
            top: `${scrollTop + containerTop + _y + e.offsetY}px`,
            left: `${scrollLeft + containerLeft + _x + 140}px`,
            zIndex: 9999,
          },
        }
      }
      // 翻译按钮
      else {
        tagInfo.value.visible = false
        tagInput.value.visible = false
      }
    }, true)
  }
}
const showSpin = ref(false)
const setShowSpin = (show: boolean) => {
  showSpin.value = show
}

async function handleTranslation(toLanguage: string) {
  console.log('选中的内容：', getStr.value)
  await new Promise(resolve => setTimeout(resolve, 1000))
  // 隐藏按钮
  tagInfo.value.visible = false
  // 开启遮罩层
  setShowSpin(true)

  //  调用翻译接口，完成翻译
  const url = 'http://localhost:8088/translate'
  const data = {
    text: getStr.value,
    prefix: toLanguage,
  }
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
    mode: 'cors',
  })
  if (!response.ok) {
    message.error('网络错误；翻译失败')
    console.error('网络错误；翻译失败')
    setShowSpin(false)
    return
  }
  const tmpData = await response.json()
  if (!tmpData || tmpData.code === 0) {
    message.error(`翻译失败:${tmpData.msg}`)
    console.error(`翻译失败:${tmpData.msg}`)
    setShowSpin(false)
    return
  }
  // 将翻译内容传递给父组件
  const translation = tmpData.data.translation as string
  emit('getTranslation', translation)
  setShowSpin(false)
  // 展示翻译弹窗
  tagInput.value = {
    visible: true,
    content: translation,
    style: {
      position: 'absolute',
      top: tagInfo.value.styleToEn.top,
      left: tagInfo.value.styleToEn.left,
      zIndex: 9999,
    },
  }
}

onMounted(() => {
  // 为PDF文件注册选中文本事件
  getSelectTxt()
})
</script>

<template>
  <div ref="pdfIframeContainer" class="iframe-container">
    <iframe ref="pdfIframe" :src="getPDFURL" style="width: 100%;height: 100%;" />
  </div>
  <NSpin :show="showSpin" description="翻译中...">
    <NButton
      v-show="tagInfo.visible" type="info" :style="tagInfo.styleToZh"
      @click="handleTranslation('translate to zh: ')"
    >
      翻译为中文
    </NButton>
    <NButton
      v-show="tagInfo.visible" type="info" :style="tagInfo.styleToEn"
      @click="handleTranslation('translate to en: ')"
    >
      翻译为英文
    </NButton>
  </NSpin>
  <NSpace class="translation-container" :style="tagInput.style">
    <!-- note: 使用v-model进行双向绑定，不然:value只能TS绑定到组件(单向) -->
    <NInput v-show="tagInput.visible" v-model:value="tagInput.content" type="textarea" placeholder="暂无翻译内容" />
  </NSpace>
</template>

<style scoped>
.iframe-container {
  width: 100%;
  height: 100%;
}

.translation-container {
  width: 20%;
}
</style>
